#include "RealTimeDealFilter.h"

#include <bondlib/BondMarketStream.h>

#include "RealTimeDealFilter.h"

namespace detail {
typedef MarketStreamInfo Record;
namespace {
kConditionType GetConditionType(const BLHCONDITION& condStr) {
  // -1:表示有问题,invalid
  // 0:表示每个债券还需要逐个检测
  // 1:表示无需检测,债券id即通过
  // 来自bool CSSVContainer::Retrieve( BLHCONDITION & condStr, std::vector<int>
  // & array_result, bool bSecondaryMarket) 开头的逻辑判断
  kConditionType type = kConditionTypeCheck;
  if (condStr.nTypeNew[0] == CBondContainer::newBondNone ||
      condStr.nRange[0] == CBondContainer::RangeNone ||
      condStr.nIssuerRating[0] == CBondContainer::RatingNone ||
      condStr.nCouponType[0] == CBondContainer::CouponNon ||
      condStr.nMunicp[0] == CBondContainer::MunicNone ||
      condStr.nInstion[0] == CBondContainer::InstNone ||
      condStr.nWarrant[0] == CBondContainer::WarrNone ||
      condStr.nRight == CBondContainer::RightNone) {
    type = kConditionTypeCheck;
  } else if (condStr.nTypeNew[0] < CBondContainer::newBondMin ||
             condStr.nTypeNew[0] > CBondContainer::newBondBroker_Second) {
    type = kConditionTypeCheck;
  } else if (condStr.nBrokId[0] == 0 && strlen(condStr.sCompanyid) == 0) {
    type = kConditionTypeCheck;
  } else if (condStr.isAllin()) {
    type = kConditionTypeAll;
  }
  return type;
}
}  // namespace
RealTimeDealFilter::RealTimeDealFilter() {
  m_bSSEFI = false;
  m_bABSFlag = false;
  BLHCONDITION blh;
  SetCondition(blh, 0);
}
void RealTimeDealFilter::SetCondition(const BLHCONDITION& blh, int corpid) {
  m_filter_type = kDealFilterTypeByCondition;
  m_condition = blh;
  m_corp_id = corpid;
  m_search_key = m_group_id = "";
  m_search_type = 0;
  m_condition_type = GetConditionType(m_condition);
  m_attend_map.clear();
}

void RealTimeDealFilter::SetSearch(const std::string& key, int type,
                                   int corpid) {
  m_filter_type = m_bSSEFI ? kDealFilterTypeBySearchInSSE
                           : (m_bABSFlag ? kDealFilterTypeBySearchABS
                                         : kDealFilterTypeBySearch);
  m_search_key = key;
  m_search_type = type;
  m_corp_id = corpid;
  m_group_id = "";
  m_condition = BLHCONDITION();
  m_condition_type = GetConditionType(m_condition);
  m_attend_map.clear();
}

void RealTimeDealFilter::SetConditionAndSearch(const std::string& key, int type,
                                               const BLHCONDITION& blh,
                                               int corpid) {
  if (m_bSSEFI || m_bABSFlag) {
    SetSearch(key, type, corpid);
    return;
  }
  m_filter_type = kDealFilterTypeBySearch;
  m_search_key = key;
  m_search_type = type;
  m_corp_id = corpid;
  m_group_id = "";
  m_condition = blh;
  m_condition_type = GetConditionType(m_condition);
  m_attend_map.clear();
}

void RealTimeDealFilter::SetAttention(const std::string& group, int corpid) {
  m_filter_type =
      m_bSSEFI ? kDealFilterTypeByAttentionInSSE : kDealFilterTypeByAttention;
  m_group_id = group;
  m_corp_id = corpid;
  m_search_key = "";
  m_search_type = 0;
  m_condition = BLHCONDITION();
  m_condition_type = GetConditionType(m_condition);

  m_attend_map.clear();
  BuildAttentionMap();
}

void RealTimeDealFilter::SetConditionAndAttention(const std::string& group,
                                                  const BLHCONDITION& blh,
                                                  int corpid) {
  m_filter_type = m_bSSEFI ? kDealFilterTypeByAttentionInSSE
                           : kDealFilterTypeByConditionAndAttention;
  m_group_id = group;
  m_corp_id = corpid;
  m_search_key = "";
  m_search_type = 0;
  m_condition = blh;
  m_condition_type = GetConditionType(m_condition);

  m_attend_map.clear();
  BuildAttentionMap();
}

void RealTimeDealFilter::SetSSEFIFlag(bool bSSEFI) { m_bSSEFI = bSSEFI; }

void RealTimeDealFilter::SetABSBondFlag(bool bABS) { m_bABSFlag = bABS; }

void RealTimeDealFilter::BuildAttentionMap() {
  /*TODO
  // 通过条件:m_company_id与m_corp_id匹配
  //		并且对应债券存在,且是银行间债券
  if ((m_filter_type != kDealFilterTypeByAttention && m_filter_type !=
  kDealFilterTypeByAttentionInSSE && m_filter_type!=
  kDealFilterTypeByConditionAndAttention) || m_group_id.empty()) return;
  CBondAttentionMap mapAtt;
  AfxGetBondAttention().GetBondAttentionByGroupID(m_group_id, mapAtt);
  map<std::string, Attention>::const_iterator itor = mapAtt.m_map.cbegin();
  for (; itor != mapAtt.m_map.cend(); itor++)
  {
          const Attention& attention = itor->second;
          int bid = AfxGetBondContainer().GetBondIndex(attention.m_BondKey,
  attention.m_ListedMarket); if (bid >= 0)
          {
                  // bool SSVContainer::Retrieve(const map<std::string,
  Attention>& mapAtt, const std::list<std::string>& m_brokls,int nType = 0 );
                  // 原始实时成交中此接口的第三个参数为0,因此移除if
  (bi.IsInterbank())的判断
                  // 同样更改参见IsDealPassed
                  const CBondInfo& bi = AfxGetBondContainer().ElementAtR(bid);
                  {
                          char keybuf[64] = { 0 };
                          int len = FIELDCOPY(keybuf, attention.m_BondKey);
                          if (len + 1 < sizeof(keybuf))
                          {
                                  keybuf[len++] = '.';
                                  len += FIELDCOPYN(keybuf + len, sizeof(keybuf)
  - len, attention.m_ListedMarket); m_attend_map[keybuf] = bid;
                          }
                  }
          }
  }
  */
}
int RealTimeDealFilter::GetBondIndex(const char* bondKey,
                                     const char* listMarket) {
  if (!m_attend_map.empty()) {
    char keybuf[64] = {0};
    int len = FIELDCOPY(keybuf, bondKey);
    if (len + 1 < sizeof(keybuf)) {
      keybuf[len++] = '.';
      len += FIELDCOPYN(keybuf + len, sizeof(keybuf) - len, listMarket);
      ComKeyIndexMap::iterator it = m_attend_map.find(keybuf);
      return it != m_attend_map.end() ? it->second : (-1);
    }
  }
  return -1;
}
bool RealTimeDealFilter::IsDealPassed(const DealIndex& id, const void* record) {
  // 对索引为id的内容为record的记录进行过滤,通过就返回true,不通过就返回false
  const MarketStreamInfo& info = *((const MarketStreamInfo*)record);
  if (m_corp_id != 0 && atoi(info.m_company_id) != m_corp_id) return false;
  switch (m_filter_type) {
    case kDealFilterTypeByAttention:       // all in
    case kDealFilterTypeByAttentionInSSE:  // 仅上交所券
    {
      if (m_filter_type == kDealFilterTypeByAttentionInSSE &&
          strcmp(info.m_body.m_listedmarket, "SSE") != 0)
        break;  // 剔除非上交所债券
      int bid = GetBondIndex(info.m_body.m_bondkey, info.m_body.m_listedmarket);
      if (!CBondContainer::instance().IsValidIndex(bid)) break;
      // bool SSVContainer::Retrieve(const map<std::string, Attention>& mapAtt,
      // const std::list<std::string>& m_brokls,int nType = 0 );
      // 原始实时成交中此接口的第三个参数为0,因此移除
      // 同样更改参见BuildAttentionMap
      const CBondInfo& bi = CBondContainer::instance().ElementAtR(bid);
      if (m_filter_type == kDealFilterTypeByAttentionInSSE &&
          bi.CheckAssetStatus(CBondContainer::AssetPri))
        break;  // 剔除私募债
      return true;
      break;
    }
    case kDealFilterTypeBySearch:       // 全市场
    case kDealFilterTypeBySearchInSSE:  // 上交所
    {
      //
      // 参见CBondContainer::RetrieveFromStatic( int bondType, const char *
      // szType, std::vector<int>& array_result )
      // 通过条件:m_company_id与m_corp_id匹配
      //			并且对应债券非增续发,非到期
      //			并且当m_search_type为0时:GetCombBondCode,GetBondShortName,GetBondJianpin之一与m_search_key匹配
      //			或者当m_search_type为1时:GetCombBondKey与m_search_key完全匹配
      if (m_filter_type == kDealFilterTypeBySearchInSSE &&
          strcmp(info.m_body.m_listedmarket, "SSE") != 0)
        break;
      int bid = CBondContainer::instance().GetBondIndex(
          info.m_body.m_bondkey, info.m_body.m_listedmarket);
      if (!CBondContainer::instance().IsValidIndex(bid)) break;
      const CBondInfo& bi = CBondContainer::instance().ElementAtR(bid);
      if (bi.IsAddIssueBond()) break;
      if (CBondContainer::GetMaturityBond(bi)) break;
      if (m_filter_type == kDealFilterTypeBySearchInSSE &&
          bi.CheckAssetStatus(CBondContainer::AssetPri))
        break;  // 剔除私募债
      if (!m_condition.isAllin()) {
        if (!CSSVContainer::IsBondPassCondition(bid, m_condition, true)) break;
      }
      if (m_search_type == 0) {
        if (strncmp(bi.GetCombBondCode(), m_search_key.c_str(),
                    m_search_key.size()) == 0 ||
            strstr(bi.GetBondShortName(), m_search_key.c_str()) ||
            strstr(const_cast<char*>(bi.GetBondJianpin().c_str()),
                   m_search_key.c_str()))
          return true;
      } else if (m_search_type == 1) {
        if (strcmp(m_search_key.c_str(), bi.GetCombBondKey()) == 0) return true;
      }
      break;
    }
    case kDealFilterTypeBySearchABS:  // ABSBond
    {
      if (strcmp(info.m_body.m_listedmarket, "CIB") != 0) break;  // 只取银行间
      int bid = CBondContainer::instance().GetBondIndex(
          info.m_body.m_bondkey, info.m_body.m_listedmarket);
      if (!CBondContainer::instance().IsValidIndex(bid)) break;
      const CBondInfo& bi = CBondContainer::instance().ElementAtR(bid);
      if (bi.IsAddIssueBond()) break;
      if (CBondContainer::GetMaturityBond(bi)) break;
      if (!bi.IsBondABS()) break;  // 非ABS券
      if (m_search_type == 0) {
        if (strncmp(bi.GetCombBondCode(), m_search_key.c_str(),
                    m_search_key.size()) == 0 ||
            strstr(bi.GetBondShortName(), m_search_key.c_str()) ||
            strstr(const_cast<char*>(bi.GetBondJianpin().c_str()),
                   m_search_key.c_str()))
          return true;
      } else if (m_search_type == 1) {
        if (strcmp(m_search_key.c_str(), bi.GetCombBondKey()) == 0) return true;
      }
      break;
    }
    default: {
      if (m_filter_type == kDealFilterTypeByConditionAndAttention) {
        if (-1 ==
            GetBondIndex(info.m_body.m_bondkey, info.m_body.m_listedmarket))
          return false;
      }
      // 参见:bool CSSVContainer::Retrieve( BLHCONDITION & condStr,
      // std::vector<int> & array_result, bool bSecondaryMarket)
      if (m_condition_type == kConditionTypeAll) {
        if (m_bABSFlag) {
          if (strcmp(info.m_body.m_listedmarket, "CIB") != 0) return false;
          int bid = CBondContainer::instance().GetBondIndex(
              info.m_body.m_bondkey, info.m_body.m_listedmarket);
          if (!CBondContainer::instance().IsValidIndex(bid)) return false;
          const CBondInfo& bi = CBondContainer::instance().ElementAtR(bid);
          if (!bi.IsBondABS()) return false;
        }
        return true;
      } else if (m_condition_type == kConditionTypeInvalid)
        return false;
      else {
        while (m_condition.nDealType[0] != 0)  // 优先判定成交类型
        {
          int nOprateType = atoi(info.m_operate);
          bool bNothingDone = info.IsDealStatusCanceled();
          bool bPass = false;
          for (int i = 0; i < _countof(m_condition.nDealType); i++) {
            switch (m_condition.nDealType[i]) {
              case 1:  // TKN
                if (!bNothingDone && nOprateType == 0) bPass = true;
                break;
              case 2:  // GVN
                if (!bNothingDone && nOprateType == 1) bPass = true;
                break;
              case 3:  // TRD
                if (!bNothingDone && nOprateType == 2) bPass = true;
                break;
              case 4:  // NothingDone
                if (bNothingDone) bPass = true;
                break;
              default:
                break;
            }
          }
          if (!bPass) return false;
          break;
        }
        int bid = CBondContainer::instance().GetBondIndex(
            info.m_body.m_bondkey, info.m_body.m_listedmarket);
        if (!CBondContainer::instance().IsValidIndex(bid)) return false;

        if (m_bSSEFI) {
          return CSSVContainer::IsSSEFIBondPassCondition(bid, m_condition,
                                                         true);
        } else if (m_bABSFlag) {
          return CSSVContainer::IsABSBondPassCondition(bid, m_condition, true);
        } else {
          return CSSVContainer::IsBondPassCondition(bid, m_condition, true);
        }
      }

      break;
    }
  }
  return false;
}
}  // namespace detail